home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-05
/
netbtime.zip
/
TIMERECV.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-03-09
|
44KB
|
936 lines
TITLE TIMERECV
PAGE 65,132
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ TIMERECV -- A TSR to Receive Periodically Broadcasted Time ║
;║ ║
;║ I am the original author of this work and hereby place it into ║
;║ the public domain. If your conscience bothers you, please feel ║
;║ free to send me $25.00 so that I may provide more such goodies. ║
;║ ║
;║ NOTE: This source code was written to be assembled with OPTASM. ║
;║ Phase errors and near jump problems will surely occur if ║
;║ MASM is used. Also, this program must be constructed as ║
;║ a .COM file. ║
;║ ║
;║ Programmer ...... George W. Mays ║
;║ Date ............ February, 1993 ║
;║ Site ............ 3314 Prince George ║
;║ San Antonio, TX 78230 ║
;║ Source .......... 80286 Assembler ║
;║ System .......... IBM PC/AT Compatible System Under MSDOS ║
;║ ║
;╚═══════════════════════════════════════════════════════════════════════════╝
.286
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
INCLUDE NETBIOS.INC
ORG 100H ;SKIP TO END OF THE PSP
ENTPT: JMP INITIALIZE ;COM FILE ENTRY ALWAYS AT 100H
COPYRIGHT DB "TIMERECV V1.0, (C) 1993, G.W. Mays",0Ah,0Dh
DB "In the Public Domain. Use Freely.",0Ah,0Dh,'$'
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Program data area. Buffers & Stack at end of resident code. │
;╘═══════════════════════════════════════════════════════════════════════════╛
;
; Data Stuff
STACKSIZE EQU 0200h ;Our stack size
VER DW 0 ;DOS version as returned
DOSMAJOR DB 0 ;DOS major version number
DOSMINOR DB 0 ;DOS minor version number
REDIRACTIVE DB 0 ;Redirector flag
HAVEBUFF DB 0 ;Flag, data has been received
LASTSTATUS DB 0 ;Completion code from last recv
NAMENUM DB 0 ;Name Number returned by NB
TEN DB 10 ;Handy constant 10 decimal
ZERO DB 0 ;Handy constant 0
HUNDRED DW 100 ;Handy constant 100 decimal
SEMAPHORE DW 0FFFFh ;Serialize interrupt processing
SAVE_SP DW 0 ;Stack save cells
SAVE_SS DW 0
BUFF DB " " ;Data buff for NB receive
DATETIME DB " " ;Copy of above data buffer
PREV1Ch DD 0 ;Addr of original 1C Handler
PREV28h DD 0 ;Addr of original 28 Handler
INDOS DD 0 ;Addr of INDOS flag
CRIT DD 0 ;Addr of critical error flag
COUNTER DW 0 ;Tick counter
NTICKS DW 182 ;Tick count to trip action
MYNAME DB "TIMECLIENT " ;My NETBIOS name
HISNAME DB "TIMESERVER " ;Sender NETBIOS name
CB NCB <> ;Our NCB
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Control is passed here by DOS via INT 0x1C (the Timer interrupt). │
;│ │
;│ A quick word about stack handling.... We don't want to risk blowing │
;│ the stack on the poor guy who gets interrupted. So we use our own │
;│ stack. However, that presents a problem since the INT 1C handler │
;│ could conceivably be interrupted by INT 28 processing (and vice- │
;│ versa). To avoid the conflicts that such a scenario would give rise │
;│ to, access to our stack is serialized by use of a semaphore. In this │
;│ way, only the first guy to the semaphore gets control of it and hence │
;│ implicitly is the one who may use our stack. Those failing to get │
;│ control of the semaphore simply say "never mind" and skip their │
;│ attempts at processing for one service cycle. │
;│ │
;╘═══════════════════════════════════════════════════════════════════════════╛
INT_1C PROC FAR
NOP ; INT 3 ;Debug or NOP
PUSHF ;Save flags
PUSH DS
PUSH AX
; Bump & Test Counter
MOV AX,CS ;Set up addressing
MOV DS,AX
MOV AX,COUNTER ;Bump counter
INC AX
MOV COUNTER,AX
CMP AX,NTICKS ;Have we hit "NTICKS"?
JB RESTORE ;No, restore & return
INC CS:SEMAPHORE ;Enqueue the stack
JNZ DEQUEUE ;Busy?
;No, fall thru...
; Time to Examine Broadcasted Date/Time
CLI ;Set our stack
MOV CS:SAVE_SP,SP ;Save stack address
MOV SP,SS ;
MOV CS:SAVE_SS,SP
MOV SP,CS
MOV SS,SP
MOV SP,OFFSET STACKTOP ;
STI
PUSH ES ;Save registers
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
; The Reason We Came ----------------------------
MOV AL,00h ;00h means DOS not busy
CALL DOTIME ;Process date/time received
; -----------------------------------------------
POP BX ;Restore registers
POP CX
POP DX
POP SI
POP DI
POP ES
CLI
MOV SP,CS:SAVE_SS ;Restore stack address
MOV SS,SP
MOV SP,CS:SAVE_SP
STI
DEQUEUE:
DEC CS:SEMAPHORE ;Dequeue
RESTORE:
POP AX ;Restore registers
POP DS
POPF ;Restore flags and
JMP CS:[PREV1Ch] ; percolate the call
INT_1C ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Control is passed here by DOS via INT 0x28 (the Idle interrupt). │
;│ │
;│ This routine is a bit different from the timer interrupt service │
;│ routine. It does NOT bump the COUNTER; it simply tests to see if │
;│ COUNTER has already been bumped past NTICKS by the timer interrupt │
;│ service routine. This happens, presumably, when the system is at │
;│ the command prompt (i.e. it is "in DOS") and hence we cannot do │
;│ our DOS calls from the timer interrupt routine. The timer ticks │
;│ continue to count - we just can't call DOS to set the date/time │
;│ so we continue to pop in and out waiting for the INDOS flag to │
;│ clear, which it won't when you're waiting at the command prompt. │
;│ Alas, DOS generates this interrupt (28h) periodically while it is │
;│ servicing buffered keyboard input, which, as fate would have it, │
;│ is just what COMMAND.COM is waiting on at the command prompt. │
;│ │
;╘═══════════════════════════════════════════════════════════════════════════╛
INT_28 PROC FAR
PUSHF ;Save flags
PUSH DS
PUSH AX
INC CS:SEMAPHORE ;Enqueue the stack
JNZ SKIPIT ; busy...
; Test Counter
MOV AX,CS ;Set up addressing
MOV DS,AX
MOV AX,COUNTER ;Bump counter
CMP AX,NTICKS ;Have we hit "NTICKS"?
JB SKIPIT ;No, restore & return
;Yes, fall thru...
; Time to Examine Broadcasted Date/Time
CLI ;Set our stack
MOV CS:SAVE_SP,SP ;Save stack address
MOV SP,SS ;
MOV CS:SAVE_SS,SP
MOV SP,CS
MOV SS,SP
MOV SP,OFFSET STACKTOP ;
STI
PUSH ES ;Save registers
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
; The Reason We Came ----------------------------
MOV AL,01h ;01h means DOS not busy
CALL DOTIME ;Process date/time received
; -----------------------------------------------
POP BX ;Restore registers
POP CX
POP DX
POP SI
POP DI
POP ES
CLI
MOV SP,CS:SAVE_SS ;Restore stack address
MOV SS,SP
MOV SP,CS:SAVE_SP
STI
SKIPIT:
DEC CS:SEMAPHORE ;Dequeue
POP AX ;Restore registers
POP DS
POPF ;Restore flags and
JMP CS:[PREV28h] ; percolate the call
INT_28 ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Get date & time from BIOS; pack 'em up & ship 'em out.... │
;╘═══════════════════════════════════════════════════════════════════════════╛
DOTIME PROC NEAR
NOP ; INT 3 ;Debug or NOP
CMP HAVEBUFF,00h ;Do we have date/time yet?
JZ BEATFEET ;No, BEATFEET
LES BX,INDOS ;Did we interrupt DOS?
CMP AL,BYTE PTR ES:[BX]
JNE BEATFEET ;Yes, BEATFEET
LES BX,CRIT ;Critical error handler active?
CMP BYTE PTR ES:[BX],00h
JNZ BEATFEET ;Yes, BEATFEET
; OK - at this point we have received a date/time broadcast, and we know that
; we're not stepping on DOS or the Critical Error Handler.
CMP LASTSTATUS,00h ;If bad last recv status...
JNE NEWRECEIVE ;Just crank up a new receive
CALL VALIDATE ;Validate received data
JC NEWRECEIVE ;Whoa! Something funky
;
CALL CONVERTDATE ;Good D/T frame, set D/T.
MOV AH,2Bh
INT 21h
CALL CONVERTTIME
MOV AH,2Dh
INT 21h
XOR AX,AX
MOV COUNTER,AX ;Zero counter
;
NEWRECEIVE:
CALL CLEARNCB ;Prepare NCB
CALL BUILDRECEIVE
MOV HAVEBUFF,00h ;Clear HAVEBUFF flag
CALL CALLNB ;Call NETBIOS
BEATFEET:
RET ;Return
DOTIME ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ NBPOST Function --- NETBIOS posts us here upon SEND DATAGRAM completion. │
;╘═══════════════════════════════════════════════════════════════════════════╛
NBPOST PROC NEAR
STI ;Reenable interrupts
PUSH DS ;Save regs
PUSH ES
PUSH AX
PUSH CX
PUSH DI
PUSH SI
MOV AX,CS ;Set ES = DS = CS
MOV DS,AX
MOV ES,AX
MOV AL,CB.NCB_RETCODE ;Tuck away completion status
MOV LASTSTATUS,AL
MOV AL,CB.NCB_COMMAND
MOV HAVEBUFF,AL ;Set HAVEBUFF flag
MOV CX,16 ;Save data received
MOV DI,OFFSET DATETIME
MOV SI,OFFSET BUFF
CLD
REP MOVSB
POP SI
POP DI
POP CX
POP AX ;Restore regs
POP ES
POP DS
IRET ;Return from interrupt
NBPOST ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ CLEARNCB Function --- Fill the NCB with binary zeroes. │
;╘═══════════════════════════════════════════════════════════════════════════╛
CLEARNCB PROC NEAR
PUSHF ;Save regs & flags
PUSH ES
PUSH DI
PUSH CX
PUSH AX
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET CB ;Zero the NCB
MOV CX,NCB_SIZE
XOR AL,AL
CLD
REP STOSB
POP AX ;Restore regs & flags
POP CX
POP DI
POP ES
POPF
RET
CLEARNCB ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ BUILDRECEIVE Function --- Fill in the NCB for a Receive Datagram │
;╘═══════════════════════════════════════════════════════════════════════════╛
BUILDRECEIVE PROC NEAR
MOV AH,NAMENUM ;Name Number
MOV CB.NCB_NUM,AH
MOV CB.NCB_LENGTH,16 ;Length
MOV AX,CS
MOV ES,AX
MOV CB.NCB_BUFF_SEG,AX ;Buffer Address and
MOV CB.NCB_POST_SEG,AX ; Post Address
MOV AX,OFFSET BUFF
MOV CB.NCB_BUFF_OFF,AX
MOV AX,OFFSET NBPOST
MOV CB.NCB_POST_OFF,AX
;Function Code
MOV AL,RECEIVEDATAGRAM+NCB_NOWAIT
MOV CB.NCB_COMMAND,AL
MOV BX,OFFSET CB ;ES:BX -> NCB
RET
BUILDRECEIVE ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ VALIDATE Function --- Validate the D/T buff contents. │
;╘═══════════════════════════════════════════════════════════════════════════╛
VALIDATE PROC NEAR
CMP DATETIME+00h,'D' ;Validate received data
JNE FUNKY
CMP DATETIME+01h,'/'
JNE FUNKY
CMP DATETIME+02h,'T'
JNE FUNKY
CMP DATETIME+03h,00h
JNE FUNKY
CMP DATETIME+0Ch,00h
JNE FUNKY
CMP DATETIME+0Fh,00h
JNE FUNKY
MOV AH,DATETIME+04h ;Form checksum
MOV AL,DATETIME+05h
MOV BH,DATETIME+06h
MOV BL,DATETIME+07h
ADD AX,BX
MOV BH,DATETIME+08h
MOV BL,DATETIME+09h
ADD AX,BX
MOV BH,DATETIME+0Ah
MOV BL,DATETIME+0Bh
ADD AX,BX
CMP AX,WORD PTR DATETIME+0Dh
JNE FUNKY
CLC ;Happy stuff, clear carry
RET
FUNKY:
STC ;Invalide stuff, set carry
RET
VALIDATE ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ CONVERTTIME Function --- Take TIME from D/T buff, Convert for DOS call. │
;╘═══════════════════════════════════════════════════════════════════════════╛
CONVERTTIME PROC NEAR
MOV AL,DATETIME+08h ;Hour
SHR AL,4
MUL TEN
MOV AH,DATETIME+08h
AND AH,0Fh
ADD AL,AH
MOV CH,AL
MOV AL,DATETIME+09h ;Minutes
SHR AL,4
MUL TEN
MOV AH,DATETIME+09h
AND AH,0Fh
ADD AL,AH
MOV CL,AL
MOV AL,DATETIME+0Ah ;Seconds
SHR AL,4
MUL TEN
MOV AH,DATETIME+0Ah
AND AH,0Fh
ADD AL,AH
MOV DH,AL
MOV DL,ZERO
RET
CONVERTTIME ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ CONVERTDATE Function --- Take DATE from D/T buff, Convert for DOS call. │
;╘═══════════════════════════════════════════════════════════════════════════╛
CONVERTDATE PROC NEAR
MOV AL,DATETIME+04h ;Century
SHR AL,4
MUL TEN
MOV AH,DATETIME+04h
AND AH,0Fh
ADD AL,AH
XOR AH,AH
MUL HUNDRED
MOV CX,AX
MOV AL,DATETIME+05h ;Year
SHR AL,4
MUL TEN
MOV AH,DATETIME+05h
AND AH,0Fh
ADD AL,AH
XOR AH,AH
ADD CX,AX
MOV AL,DATETIME+06h ;Month
SHR AL,4
MUL TEN
MOV AH,DATETIME+06h
AND AH,0Fh
ADD AL,AH
MOV DH,AL
MOV AL,DATETIME+07h ;Day
SHR AL,4
MUL TEN
MOV AH,DATETIME+07h
AND AH,0Fh
ADD AL,AH
MOV DL,AL
RET
CONVERTDATE ENDP
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ CALL NETBIOS - This routine is called to send an NCB to the NETBIOS. ║
;║ If a redirector is loaded use int 2Ah otherwise use int 5Ch. ║
;║ ║
;║ On entry: ║
;║ ES:BX addr of NCB ║
;║ On exit: ║
;║ AX return code ║
;╚═══════════════════════════════════════════════════════════════════════════╝
CALLNB PROC NEAR
CMP REDIRACTIVE,0 ;Is a redirector active?
JNE THRUREDIR
INT 5Ch
RET
THRUREDIR:
MOV AX,0400h
INT 2Ah
RET
CALLNB ENDP
;╞═══════════════════════════════════════════════════════════════════════════╡
PC = $ ;End of Code, OFFSET -> PC
STACKBOT = PC ;Stacks starts after code
PC = PC + STACKSIZE ; and is STACKSIZE bytes long
STACKTOP = PC ;STACKTOP1 here since stack
; grows downward
LASTBYTE = PC ;LASTBYTE in resident code
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ Initialization Procedure ║
;╚═══════════════════════════════════════════════════════════════════════════╝
INITIALIZE PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG ;Set by loader.
NOP ; INT 3 ;Debug or NOP
MOV AX,CS
MOV DS,AX
MOV AH,9
MOV DX,OFFSET COPYRIGHT
INT 21H
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Pick up parameters from the command line (options or group name suffix) │
;╘═══════════════════════════════════════════════════════════════════════════╛
GETPARMS: ;Command line parms reside in
PUSH 0080h ; the PSP @ offset 0x80
CALL GETOPT ;Process parms
OR AH,AH
JZ SUCCESS
PUSH OFFSET CS:ABANDON ;Abend
CALL FAILPROG
SUCCESS:
OR AL,AL ;Check result
JZ GOTNAME ;ZERO, means no suffix char
MOV BX,OFFSET MYNAME ;BX->MYNAME
MOV CX,16 ;CX= length of MYNAME (16)
JMP SPACELOOP ;Begin look for first blank
NEXTINNAME:
DEC CX ;Decrement count
JZ NOBLANKS ;If it goes to 0, no find!
INC BX ;Bump pointer into MYNAME
SPACELOOP:
CMP BYTE PTR [BX],' ' ;Is the char blank?
JNE NEXTINNAME ;NO, loop back to next char
JMP BLANKFOUND ;YES, alright! Go plug suffix
NOBLANKS:
PUSH OFFSET CS:NAMETOOLONG ;MYNAME contains no blanks!
CALL FAILPROG ;Die
BLANKFOUND:
MOV BYTE PTR [BX],AL ;Put suffix on group name
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Check to see that NETBIOS is active. Check for a redirector. │
;╘═══════════════════════════════════════════════════════════════════════════╛
GOTNAME:
CALL CHECKDOS ;DOS better be 3.1 or greater
CALL CHKNETB ;See if NETBIOS is in here
JNC NBTHERE
PUSH OFFSET CS:NASTYGRAM ;Whoa! No NETBIOS!
CALL FAILPROG ;Die.
NBTHERE:
MOV AH,0
INT 2Ah ;Check for redirector
MOV REDIRACTIVE,AH
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Add our name to the NETBIOS name table. │
;╘═══════════════════════════════════════════════════════════════════════════╛
CALL CLEARNCB ;Zero the NCB first
MOV AL,ADDGROUPNAME ;Fill in NCB fields
MOV CB.NCB_COMMAND,AL
MOV DI,OFFSET CB.NCB_NAME
MOV SI,OFFSET MYNAME
MOV CX,16
CLD
REP MOVSB
MOV BX,OFFSET CB
CALL CALLNB ;Call NETBIOS
MOV AL,CB.NCB_RETCODE
OR AL,AL ;Check status
JZ ADDWASOK
PUSH OFFSET CS:ADDFAILED ;Whoa! It didn't work.
CALL FAILPROG ;Die.
ADDWASOK:
MOV AL,CB.NCB_NUM ;Grab "name number" returned
MOV NAMENUM,AL ; and save it for use later.
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Get the current address of Int 1C and save (it's the timer interrupt) │
;╘═══════════════════════════════════════════════════════════════════════════╛
MOV AH,35h ;Get Int vector
MOV AL,1Ch ;For this Int
INT 21h ;Result in ES:BX
ASSUME ES:NOTHING
MOV WORD PTR PREV1Ch[0],BX ;offset
MOV WORD PTR PREV1Ch[2],ES ;segment
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Get the current address of Int 28 and save (it's the idle interrupt) │
;╘═══════════════════════════════════════════════════════════════════════════╛
MOV AH,35h ;Get Int vector
MOV AL,28h ;For this Int
INT 21h ;Result in ES:BX
MOV WORD PTR PREV28h[0],BX ;offset
MOV WORD PTR PREV28h[2],ES ;segment
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Free our environment segment to save a little space. │
;╘═══════════════════════════════════════════════════════════════════════════╛
PUSH DS
MOV AH,62h ;Get PSP address
INT 21h ;
MOV DS,BX
MOV ES,DS:2Ch ;ES<-Env Seg Addr
MOV AH,49h ;Free memory alloc
INT 21h ;
POP DS
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Get the address of the INDOS flag. │
;╘═══════════════════════════════════════════════════════════════════════════╛
MOV AH,34h ;Get InDos function
INT 21h ; from DOS
MOV WORD PTR INDOS[0],BX
MOV WORD PTR INDOS[2],ES
PUSH DS
MOV AX,5D06h ;Get Critical Error function
INT 21h
MOV WORD PTR CS:CRIT[0],SI
MOV WORD PTR CS:CRIT[2],DS
POP DS
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Hang a RECEIVE DATAGRAM on the line. │
;╘═══════════════════════════════════════════════════════════════════════════╛
TRYTORECEIVE:
CALL CLEARNCB ;Zero the NCB first
CALL BUILDRECEIVE
MOV AL,RECEIVEDATAGRAM+NCB_NOWAIT
MOV CB.NCB_COMMAND,AL
MOV HAVEBUFF,AL
CALL CALLNB ;Call NETBIOS
POLLNET:
MOV AL,CB.NCB_CMD_CPLT ;Poll for completion
CMP AL,0FFh ;Still "in progress"?
JNE GOTMSG ;NO, it finished
MOV AH,01h ;YES, Test keyboard
INT 16h ;Via the BIOS
JZ POLLNET ;Nothing pending, loop back
MOV DI,OFFSET FUNKYNCB ;Keystroke detected...
MOV CX,NCB_SIZE ;Zero the alternate NCB
XOR AL,AL
CLD
REP STOSB
MOV BX,OFFSET FUNKYNCB
MOV AL,CANCELCMD ;Cancel the outstanding
MOV FUNKYNCB.NCB_COMMAND,AL ; RECEIVEDATAGRAM command
MOV FUNKYNCB.NCB_BUFF_OFF,OFFSET CB
MOV FUNKYNCB.NCB_BUFF_SEG,DS
MOV AH,09h
MOV DX,OFFSET CANCELLING
INT 21h
CALL CALLNB
PUSH OFFSET CS:KEYSTROKE
CALL FAILPROG
GOTMSG:
MOV AL,CB.NCB_RETCODE
OR AL,AL ;Check status
JZ REQWASOK
PUSH OFFSET CS:REQFAILED ;Whoa! It didn't work.
CALL FAILPROG ;Die.
REQWASOK:
PUSH CS
POP ES
MOV CX,16 ;Save data received
MOV DI,OFFSET DATETIME
MOV SI,OFFSET BUFF
CLD
REP MOVSB
CALL VALIDATE ;Validate received data
JC TRYTORECEIVE
;
MOV CH,DATETIME+04h ;Set date in CMOS
MOV CL,DATETIME+05h
MOV DH,DATETIME+06h
MOV DL,DATETIME+07h
MOV AH,05h
INT 1Ah
CALL CONVERTDATE ;Set date in DOS
MOV AH,2Bh
INT 21h
MOV CH,DATETIME+08h ;Set time in CMOS
MOV CL,DATETIME+09h
MOV DH,DATETIME+0Ah
MOV DL,DATETIME+0Bh
MOV AH,03h
INT 1Ah
CALL CONVERTTIME ;Set time in DOS
MOV AH,2Dh
INT 21h
XOR AX,AX
MOV COUNTER,AX ;Zero counter
MOV LASTSTATUS,0FFh
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Plug ourselves into DOS Idle Interrupt (Interrupt 28). │
;╘═══════════════════════════════════════════════════════════════════════════╛
PUSH DS
PUSH CS
POP DS
MOV DX,OFFSET INT_28 ;INT_28 is ISR entry
MOV AH,25h ;Set Interrupt vector
MOV AL,28h ; 28h.
INT 21h ;
POP DS
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Plug ourselves into DOS Timer Interrupt (Interrupt 1C). │
;╘═══════════════════════════════════════════════════════════════════════════╛
PUSH DS
PUSH CS
POP DS
MOV DX,OFFSET INT_1C ;INT_1C is ISR entry
MOV AH,25h ;Set Interrupt vector
MOV AL,1Ch ; 1Ch.
INT 21h ;
POP DS
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ Terminate and stay resident. │
;╘═══════════════════════════════════════════════════════════════════════════╛
MOV AX,3100H
MOV DX,(OFFSET LASTBYTE - OFFSET CSEG + 15) SHR 4
INT 21H
INITIALIZE ENDP
ABANDON DB "TIMERECV did NOT remain resident",0Ah,0Dh,'$'
NASTYGRAM DB "NETBIOS is NOT active on this system",0Ah,0Dh,'$'
ADDFAILED DB "NETBIOS Add Name failed",0Ah,0Dh,'$'
REQFAILED DB "NETBIOS Recieve Datagram failed",0Ah,0Dh,'$'
NAMETOOLONG DB "NETBIOS Name too long to add suffix",0Ah,0Dh,'$'
CANCELLING DB "Cancelling Receive Datagram request",0Ah,0Dh,'$'
KEYSTROKE DB "Initialization terminated by keystroke",0Ah,0Dh,'$'
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ FAILPROG --- Display string (terminated with "$") on console, then │
;│ exit the program with nonzero condition code. │
;╘═══════════════════════════════════════════════════════════════════════════╛
FAILPROG PROC NEAR
PUSH SP
POP BX
MOV DX,WORD PTR [BX+2] ;Get offset of string
PUSH CS ;Assume offset w/in this code
POP DS
MOV AH,09h ;Display String function
INT 21h ; of DOS
MOV AH,4Ch ;Terminate a Process func
MOV AL,01h ; of DOS
INT 21h ;
INT 20h ;Just to be safe....
FAILPROG ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ CHECKDOS --- Get the DOS version. Bomb if < DOS 3.10. │
;╘═══════════════════════════════════════════════════════════════════════════╛
CHECKDOS PROC NEAR
PUSH BP ;Save register(s)
MOV BP,SP
PUSH CX
PUSH BX
PUSH AX
MOV AH,30h ;Get DOS Version
INT 21h
MOV CS:VER,AX ;Save results
MOV CS:DOSMAJOR,AL
MOV CS:DOSMINOR,AH
CMP AL,3 ;Check major level
JL VERCHOKE ;<3, VERCHOKE
JNE VEROK ;>3, VEROK
CMP AH,1 ;Check minor level for 3.x
JGE VEROK ;VEROK if 3.1 or better
VERCHOKE:
PUSH OFFSET CS:VERMSG ;Push offset of nastygram
CALL FAILPROG ;And kiss off....
VEROK:
POP AX ;Restore registers
POP BX
POP CX
MOV SP,BP ;Restore stack
POP BP
RET ;Return to caller
CHECKDOS ENDP
VERMSG DB "DOS Version MUST be 3.1 or greater$"
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ Check For NETBIOS Installed in System ║
;║ Return with CARRY SET if NOT installed ║
;╚═══════════════════════════════════════════════════════════════════════════╝
CHKNETB PROC NEAR
MOV AH,35h ;Who's plugged into INT 5C?
MOV AL,5Ch
INT 21h
MOV AX,ES
CMP AX,0000h
JE NOTKOSHER
CMP AX,0F000h
JE NOTKOSHER
ITSPLUGGED:
PUSH CS
POP ES
MOV DI,OFFSET FUNKYNCB ;Zero the NCB
MOV CX,NCB_SIZE
XOR AL,AL
CLD
REP STOSB
MOV BX,OFFSET FUNKYNCB
MOV AL,0FFh
MOV FUNKYNCB.NCB_COMMAND,AL
MOV AL,00h
INT 5Ch ;Check it.
MOV AL,FUNKYNCB.NCB_RETCODE
CMP AL,03h ;Zero ?
JNE NOTKOSHER ;Yes, so not installed.
CLC
RET
NOTKOSHER:
STC
RET
FUNKYNCB NCB <> ;NCB with FUNKY command
; to test things out
CHKNETB ENDP
;╒═══════════════════════════════════════════════════════════════════════════╕
;│ GETOPT Function --- Get options or NETBIOS group name to use │
;╘═══════════════════════════════════════════════════════════════════════════╛
GETOPT PROC NEAR
ENTER WORD PTR 0,0
; Stack frame STRING offset +4
MOV AL,BYTE PTR [BP+4] ;STRING
MOV BL,AL ;BX points to parm line
XOR BH,BH
MOV AL,BYTE PTR [BX] ;CX contains line length
MOV CL,AL
XOR CH,CH
INC BX ;BX += 1
JMP SHORT PASSONE ;Find 1st nonblank char
BLANKLOOP:
MOV AX,CX ;N
DEC CX ;N
OR AX,AX
JE ENDLOOP
INC BX ;P
PASSONE:
CMP BYTE PTR [BX],' '
JE BLANKLOOP
ENDLOOP:
CMP CX,0 ;N
JNE FIND
XOR AX,AX ;Return a ZERO which
LEAVE ; indicates "no suffix"
RET
FIND:
MOV AL,BYTE PTR [BX]
CMP AL,'/'
JE ITSASLASH
CMP AL,'?'
JNE SUFFIX
CALL SHOWHELP
JMP OPTEXIT
; Seems to be the NETBIOS name suffix to use
SUFFIX:
PUSH AX
CALL TOUPPER
ADD SP,2
MOV BYTE PTR [BX],AL
CMP AL,'0' ;Validate the suffix
JL BADCHAR ; character. 0-9 or A-Z.
CMP AL,'9'
JLE CHAROK
CMP AL,'A'
JL BADCHAR
CMP AL,'Z'
JLE CHAROK
BADCHAR:
PUSH OFFSET CS:INVALIDMSG ;Say "Bad Suffix Char..."
CALL FAILPROG
CHAROK:
XOR AH,AH
MOV AL,BYTE PTR [BX]
LEAVE
RET
ITSASLASH:
INC BX ;Look at option char
MOV AL,BYTE PTR [BX] ;Make it upper case
CMP AL,'?'
JNE NOTHELP
CALL SHOWHELP
JMP OPTEXIT
NOTHELP:
PUSH AX
CALL TOUPPER
ADD SP,2
CMP AL,'U' ;/U ?
JE DOUNLOAD ;YES, go do unload
CALL SHOWHELP ;NO, show help
JMP OPTEXIT ; and then exit.
DOUNLOAD:
CALL UNLOAD ;Invoke unload logic
OPTEXIT:
MOV AH,01h
XOR AL,AL ;Return a ZERO which
LEAVE ; indicates "no suffix"
RET
NOP
GETOPT ENDP
INVALIDMSG DB "Invalid name suffix character.",0Ah,0Dh,'$'
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ Show the Help Text ║
;╚═══════════════════════════════════════════════════════════════════════════╝
SHOWHELP PROC NEAR
MOV DX,OFFSET CS:HELPLINE ;Get offset of help string
MOV AH,09h ;Display String function
INT 21h ; of DOS
RET
SHOWHELP ENDP
HELPLINE DB " To LOAD-> TIMERECV <x> where x=name suffix"
DB 0Ah,0Dh
DB "Or To UNLOAD-> TIMERECV /U"
DB 0Ah,0Dh,'$'
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ Request TIMERECV Unload From Memory ║
;╚═══════════════════════════════════════════════════════════════════════════╝
UNLOAD PROC NEAR
PUSH CS:OFFSET CS:NOTYET ;Get offset of "Not yet..."
CALL FAILPROG ;Die.
UNLOAD ENDP
NOTYET: DB "Unload of TIMERECV not yet supported",0Ah,0Dh,'$'
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ Convert Character in AL to Upper Case ASCII ║
;╚═══════════════════════════════════════════════════════════════════════════╝
TOUPPER PROC NEAR
CMP AL,'a' ;LESS THAN 'a'?
JL ITSOK ;YES, DOESN'T NEED CONVERTING
CMP AL,'z' ;NO, GREATER THAN 'z'?
JG ITSOK ;YES, DOESN'T NEED CONVERTING
SUB AL,32 ;NO, IT'S BETWEEN 'a' & 'z'
ITSOK: RET ;Return to caller
TOUPPER ENDP
CSEG ENDS
END ENTPT
;╔═══════════════════════════════════════════════════════════════════════════╗
;║ End of Program --- TIMERECV ║
;╚═══════════════════════════════════════════════════════════════════════════╝